package com.bjl.service.imp;

import com.alibaba.fastjson.JSONObject;
import com.bjl.dao.UserDao;
import com.bjl.entity.User;
import com.bjl.service.UserService;
import io.rong.models.TokenResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import orm.base.Ex.BaseServiceEx;
import orm.dictionary.OnlineStatus;
import orm.dictionary.Role;
import orm.service.RedisService;
import orm.utils.BeanToMapUtil;
import orm.utils.ChartUtils;
import orm.utils.ExportExcelUtils;
import orm.utils.SerializeUtil;
import wangchao.tools.CreateKey;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户service
 * Created by ashin on 2017/11/9.
 */

@Service
@Scope("prototype")
public class UserServiceImp extends BaseServiceEx implements UserService {

    @Autowired
    UserDao userDao;

    @Autowired
    ChartUtils chartUtils;

    @Override
    public void init() {
        super.init(userDao);
    }

    @Override
    public JSONObject login(Map map, HttpSession session, boolean isBackend) throws Exception {
        if (map.get("userName") == null)
            return this.codeMess(eCode, "用户名不能为空");
        if (map.get("passWord") == null)
            return this.codeMess(eCode, "密码不能为空");
        User user = userDao.selectp(map);
        if (user == null)
            return this.codeMess(eCode, "用户名或密码不正确");
        if (isBackend && !Role.manageGroup(user.getRole())) {
            return this.codeMess(eCode, "抱歉，您的权限不够");
        }
        //生成token
        String token = CreateKey.getRandomString(16);
        //如果重复登录，先删除原先该用户的token
        if (user.getToken() != null) {
            redisService.del(user.getToken().getBytes());
        }

        //状态改为在线
        user.setOnlineStatus(String.valueOf(OnlineStatus.onLine));
        //将新的token保存到数据库
        user.setToken(token);
        user.setPhone(map.get("phone") == null ? "其他" : map.get("phone").toString());
        user.setLastLoginTime(now());
        userDao.updatep(BeanToMapUtil.convertBean(user));
        JSONObject jsonObject = new JSONObject();
        TokenResult tokenResult = chartUtils.getUserToken(user.getRealName(), user.getId());
        if (tokenResult.getCode() != 200)
            jsonObject.put("chart_token", tokenResult.getErrorMessage());
        jsonObject.put("chart_token", tokenResult.getToken());
        user.setChart_token(tokenResult.getToken());
        //存入redis
        redisService.set(token.getBytes(), SerializeUtil.serialize(user), RedisService.TWO_HOURS);
        session.setAttribute("user", user);
        jsonObject.put("token", token);
        jsonObject.put("msg", "登录成功");
        return this.codeData(jsonObject);
    }

    @Override
    public JSONObject logout(Map map, HttpSession session) throws Exception {
        session.removeAttribute("user");
        if (map.get("token") != null)
            redisService.del(map.get("token").toString().getBytes());
        return this.codeMess(sCode, "注销成功");
    }

    @Override
    public JSONObject register(Map map, HttpSession session) throws Exception {
        if (map.get("userName") == null) {
            return this.codeMess(eCode, "用户名不能为空");
        }
        if (map.get("passWord") == null) {
            return this.codeMess(eCode, "密码不能为空");
        }

        Map userMap = new HashMap();
        userMap.put("userName", map.get("userName"));
        User _user = userDao.selectp(userMap);
        if (_user != null) {
            return this.codeMess(eCode, "该用户已存在");
        }
        userMap.put("passWord", map.get("passWord"));
        //如果填写了邀请码,验证邀请码是否正确,如果不正确,返回。
        if (map.get("invCode") != null) {
            userMap = new HashMap();
            userMap.put("invCode", map.get("invCode"));
            //用户必须是管理层，才有效(isManager = 1 是管理层)
            userMap.put("isManager", 1);
            User invUser = userDao.selectp(userMap);
            if (invUser == null) {
                return this.codeMess(eCode, "您的邀请码填写有误");
            } else {

                //邀请码重置
                Map invUserMap = new HashMap();
                invUserMap.put("id", invUser.getId());
                invUserMap.put("invCode", CreateKey.getRandomNum(6));
                invUserMap.put("token", invUser.getToken());
                JSONObject jsonObject = this.updatep(invUserMap);
                if (jsonObject.getInteger("code") == sCode) {
                    refreshNewUserIntoRedis(invUser);
                }

                //邀请人重新赋值
                map.put("referrerId", invUser.getId());
                //生成我的邀请码
                map.put("invCode", CreateKey.getRandomNum(6));
                //权限(vip)
                map.put("role", map.get("role") == null ? String.valueOf(Role.vip) : map.get("role"));
                //最上级leader
                map.put("leader", findTopReferrerId(invUser).getId());
            }
        } else {
            //权限(默认普通用户)
            map.put("role", map.get("role") == null ? String.valueOf(Role.user) : map.get("role"));
        }
        //昵称
        map.put("realName", map.get("userName"));

        int ret = userDao.insertp(map);
        if (ret == -1)
            return this.codeMess(eCode, "连接超时,注册失败!");
        else
            return this.codeMess(sCode, "注册成功");
    }

    @Override
    public User findTopReferrerId(User user) throws Exception {
        if (user == null)
            return null;
        return findNextReferrer(user);
    }

    @Override
    public List<User> findAllReferrerId(User user) throws Exception {
        if (user == null)
            return null;
        List<User> userList = new ArrayList<>();
        return findAllNextReferrer(user, userList);
    }


    @Override
    @Transactional
    public JSONObject update(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        if (map.size() == 1)
            return this.codeMess(eCode, "修改失败,参数有误");
        if (map.get("id") == null)
            map.put("id", user.getId());
        if (map.get("invCode") != null) {
            //先判断这个邀请码存在不存在
            Map userMap = new HashMap();
            userMap.put("invCode", map.get("invCode"));
            User invUser = userDao.selectp(userMap);
            if (invUser == null)
                return this.codeMess(eCode, "您的邀请码填写有误");
            else {
                //邀请人重新赋值
                map.put("referrerId", invUser.getId());
                //最上级leader
                map.put("leader", findTopReferrerId(invUser).getId());
                map.put("invCode", CreateKey.getRandomNum(6));
                map.put("role", String.valueOf(Role.vip));

                //邀请码重置
                Map invUserMap = new HashMap();
                invUserMap.put("id", invUser.getId());
                invUserMap.put("invCode", CreateKey.getRandomNum(6));
                JSONObject jsonObject = this.updatep(invUserMap);
                if (jsonObject.getInteger("code") == sCode) {
                    refreshNewUserIntoRedis(invUser);
                }
            }
        }

        map.remove("token");

        JSONObject jsonObject = this.updatep(map);
        if (jsonObject.getInteger("code") == sCode) {
            User updateUser = new User();
            updateUser.setId(map.get("id").toString());
//            session.setAttribute("user", refreshNewUserIntoRedis(updateUser, map));
            refreshNewUserIntoRedis(updateUser);
        }
        return jsonObject;
    }

    /**
     * 将新用户加入到redis缓存
     *
     * @param user
     * @return
     * @throws Exception
     */
    private User refreshNewUserIntoRedis(User user) throws Exception {
        Map userMap = new HashMap();
        userMap.put("id", user.getId());
        User newUser = userDao.selectp(userMap);
        if (newUser.getToken() != null)
            redisService.set(newUser.getToken().getBytes(), SerializeUtil.serialize(newUser), RedisService.TWO_HOURS);
        return newUser;
    }

    /**
     * 递归向上查询
     *
     * @param user
     * @return
     * @throws Exception
     */
    private User findNextReferrer(User user) throws Exception {
        if (String.valueOf(Role.ow).equals(user.getRole()) || user.getReferrerId() == null) {
            return user;
        }
        Map userMap = new HashMap();
        userMap.put("id", user.getReferrerId());
        User upperUser = userDao.selectp(userMap);
        //如果上级是ow，则返回此人的ID
        if (String.valueOf(Role.ow).equals(upperUser.getRole())) {
            User backUser = new User();
            backUser.setId(upperUser.getId());
            //去掉密码
            return backUser;
        } else {
            user = findTopReferrerId(upperUser);
        }
        return user;
    }

    /**
     * 向下遞歸查詢id
     *
     * @param user
     * @return
     * @throws Exception
     */
    @Override
    public List<String> findDownwardUserId(User user) throws Exception {
        if (user == null)
            return null;
        List<String> userIds = new ArrayList<>();
        return findDownwardUser(user, userIds);
    }

    /**
     * 向下遞歸查詢
     *
     * @param user
     * @return
     * @throws Exception
     */
    private List<String> findDownwardUser(User user, List<String> userIds) throws Exception {
        Map userMap = new HashMap();
        //我的下級所有用戶
        userMap.put("referrerId", user.getId());
        userIds.add("'" + user.getId() + "'");
        List<User> downwardUserList = userDao.findDownwardUser(userMap);
        for (User downwardUser : downwardUserList) {
            userIds = findDownwardUser(downwardUser, userIds);
        }
        return userIds;
    }

    /**
     * 递归向上查询(所有)
     *
     * @param user
     * @return
     * @throws Exception
     */
    private List<User> findAllNextReferrer(User user, List<User> userList) throws Exception {
        if (String.valueOf(Role.admin).equals(user.getRole()) || user.getReferrerId() == null) {
            return null;
        }
        Map userMap = new HashMap();
        userMap.put("id", user.getReferrerId());
        User upperUser = userDao.selectp(userMap);
        //如果上级是超级管理员，则返回此人的ID
        if (String.valueOf(Role.admin).equals(upperUser.getRole())) {
            userList.add(upperUser);
            return userList;
        } else {
            userList.add(upperUser);
            findAllNextReferrer(upperUser, userList);
        }
        return userList;
    }

    @Override
    public JSONObject getUnLoginUser(Map map) throws Exception {
        String realName = "游客" + CreateKey.getRandomNum(4);
        String userId = CreateKey.getRandomString(11);
        // 获取 Token 方法
        JSONObject jsonObject = new JSONObject();
        TokenResult tokenResult = chartUtils.getUserToken(realName, userId);
        if (tokenResult.getCode() != 200)
            return this.codeMess(eCode, tokenResult.getErrorMessage());
        jsonObject.put("chart_token", tokenResult.getToken());
        jsonObject.put("realName", realName);
        return jsonObject;
    }

    @Override
    public JSONObject query(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        String role = user.getRole();
        if (!Role.manageGroup(role))
            return this.codeMess(eCode, "抱歉，您的权限不足");
        if (!Role.roomManageGroup(role)) {
            map.put("referrerId", user.getId());
        } else if (String.valueOf(Role.ow).equals(role)) {
            map.put("leader", user.getId());
        }
        return super.query(map);
    }

    @Override
    public JSONObject pageQuery(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        String role = user.getRole();
        if (!Role.manageGroup(role))
            return this.codeMess(eCode, "抱歉，您的权限不足");
        if (!Role.roomManageGroup(role)) {
            map.put("referrerId", user.getId());
        } else if (String.valueOf(Role.ow).equals(role)) {
            map.put("leader", user.getId());
        }
        return super.pagequery(map);
    }

    @Override
    public JSONObject getPhoneType(HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        Map map = new HashMap();
        String role = user.getRole();
        if (!Role.manageGroup(role))
            return this.codeMess(eCode, "抱歉，您的权限不足");
        if (!Role.roomManageGroup(role)) {
            map.put("referrerId", user.getId());
        } else if (String.valueOf(Role.ow).equals(role)) {
            map.put("leader", user.getId());
        }
        return this.codeData(userDao.getPhoneType(map));
    }

    @Override
    public void exportPhoneTypeCount(HttpSession session, HttpServletResponse response) throws Exception {
        User user = (User) session.getAttribute("user");
        Map map = new HashMap();
        String role = user.getRole();
        if (!Role.manageGroup(role))
            response.getWriter().write("抱歉，您的权限不足");
        if (!Role.roomManageGroup(role)) {
            map.put("referrerId", user.getId());
        } else if (String.valueOf(Role.ow).equals(role)) {
            map.put("leader", user.getId());
        }
        List<Map> phoneTypeCountList = userDao.getPhoneType(map);
        Map<String, List<Object>> _map = formList(phoneTypeCountList);
//        ExportExcelUtils.exportWithHeadExcel("机型占比", new String[]{"使用设备", "人数"}, formList(phoneTypeCountList), response);
        ExportExcelUtils.exportWithHeadExcel("机型占比", _map.get("head").toArray(new String[]{}), _map.get("body"), response);
    }

    @Override
    public void exportQuery(Map map, HttpSession session, HttpServletResponse response) throws Exception {
        User user = (User) session.getAttribute("user");
        String role = user.getRole();
        if (!Role.manageGroup(role))
            response.getWriter().write("抱歉，您的权限不足");
        if (!Role.roomManageGroup(role)) {
            map.put("referrerId", user.getId());
        } else if (String.valueOf(Role.ow).equals(role)) {
            map.put("leader", user.getId());
        }
        List<Map> userList = userDao.exportPageQuery(map);
        Map<String, List<Object>> _map = formList(userList);
        ExportExcelUtils.exportWithHeadExcel("用户列表", _map.get("head").toArray(new String[]{}), _map.get("body"), response);
    }

    @Override
    public JSONObject checkIsUsedInvCode(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        String invCode = map.get("invCode").toString();
        String newInvCode = user.getInvCode();
        if (invCode.equals(newInvCode))
            return this.codeMess(sCode, "该邀请码未被使用");
        return this.codeMess(eCode, "对不起该激活码已被使用！");
    }

    @Override
    public JSONObject getAccountPerDay(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");

        return null;
    }

    @Transactional
    @Override
    public JSONObject refreshInvCode(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        Map userMap = new HashMap();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("invCode", CreateKey.getRandomNum(6));
        userMap.put("invCode", jsonObject.getString("invCode"));
        userMap.put("id", user.getId());
        userMap.put("token", user.getToken());
        JSONObject _jsonObject = this.updatep(userMap);
        if (_jsonObject.getInteger("code") == sCode) {
            refreshNewUserIntoRedis(user);
            return this.codeData(jsonObject);
        }
        return this.codeMess(eCode, "刷新失败");
    }
}
